import { WEBSOCKET_TYPE } from '../enums/websocket'
import { MessageCrypto } from './crypto'

export default class WebsocketClass {
  /**
   * @description: 初始化参数
   * @param {*} url ws资源路径
   * @param {*} callback 服务端信息回调
   * @param {*} enableEncryption 是否启用加密
   * @return {*}
   * @author: hacja
   */
  constructor(url, callback, enableEncryption = false) {
    console.log('🌐 WebSocket 构造函数开始执行')
    
    
    if (import.meta.env.VITE_MOCK_MODE === true || import.meta.env.VITE_MOCK_MODE === "true") {
      console.log('🌐 WebSocket 运行在 Mock 模式')
      this.mockMode = true
      return
    }
    
    this.url = url
    this.callback = callback
    this.ws = null // websocket 对象
    this.status = 0 // 连接状态: 0-关闭 1-连接 2-手动关闭
    this.ping = 25000 // 心跳时长，改为25秒，小于后端30秒的ping间隔
    this.pingInterval = null // 心跳定时器
    this.reconnect = 8000 // 重连间隔增加到8秒
    this.reconnectAttempts = 0 // 重连尝试次数
    this.maxReconnectAttempts = 15 // 增加最大重连次数
    this.reconnectBackoff = true // 是否使用退避算法
    this.connectionStable = false // 连接是否稳定
    this.stableTimeout = null // 稳定连接计时器
    
    // 加密相关配置
    this.enableEncryption = enableEncryption
    this.isEncrypted = false // 是否已建立加密通道
    this.crypto = enableEncryption ? new MessageCrypto() : null
  }

  /**
   * @description: 连接
   * @param {*}
   * @return {*}
   * @author: gumingchen
   */
  connect() {
    // 设置连接超时
    const connectionTimeout = setTimeout(() => {
      if (this.ws && this.ws.readyState !== WebSocket.OPEN) {
        console.error('🌐 WebSocket 连接超时')
        this.ws.close()
      }
    }, 15000) // 增加连接超时时间到15秒
    
    try {
      console.log('🌐 WebSocket 开始连接到:', this.url)
      this.ws = new WebSocket(this.url)
      console.log('🌐 WebSocket 对象创建成功')
      
      // 监听socket连接
      this.ws.onopen = () => {
        clearTimeout(connectionTimeout) // 清除连接超时定时器
        this.status = 1
        this.reconnectAttempts = 0 // 连接成功后重置重连计数
        console.log('🌐 WebSocket 连接成功!')
        
        // 启动心跳
        this.heartHandler()
        
        // 设置稳定连接计时器 - 连接保持10秒后才认为是稳定的
        this.stableTimeout = setTimeout(() => {
          this.connectionStable = true
          console.log('🌐 WebSocket 连接已稳定')
        }, 10000)
        
        // 如果启用了加密，添加短暂延迟后初始化加密
        if (this.enableEncryption) {
          // 重置加密状态
          this.isEncrypted = false
          console.log('🔒 加密功能已启用，准备初始化加密...')
          setTimeout(() => {
            console.log('🔒 延迟后开始初始化加密...')
            this.initEncryption()
          }, 3000) // 增加延迟到3秒，确保连接稳定
        } else {
          console.log('🔒 加密功能未启用')
        }
      }
      
      // 监听socket消息
      this.ws.onmessage = (e) => {
        try {
          console.log('🌐 WebSocket 收到原始消息:', e.data.substring(0, 100) + (e.data.length > 100 ? '...' : ''))
          const rawData = JSON.parse(e.data)
          console.log('🌐 WebSocket 收到消息类型:', rawData.type)
          
          // 处理密钥交换消息
          if (this.enableEncryption && 
             (rawData.type === WEBSOCKET_TYPE.KEY_EXCHANGE_INIT || 
              rawData.type === WEBSOCKET_TYPE.KEY_EXCHANGE_COMPLETE || 
              rawData.type === WEBSOCKET_TYPE.KEY_EXCHANGE_SUCCESS)) {
            console.log('🔒 收到密钥交换相关消息:', {
              type: rawData.type,
              hasServerPublicKey: !!rawData.serverPublicKey,
              hasSuccess: !!rawData.success
            })
            this.handleKeyExchange(rawData)
            return
          }
          
          // 解密消息或直接处理
          let data
          if (this.enableEncryption && this.isEncrypted && rawData.encrypted) {
            try {
              data = this.crypto.decryptMessage(rawData.payload)
              console.log('🔒 解密消息成功:', {
                type: WEBSOCKET_TYPE[data.type] || data.type
              })
            } catch (error) {
              console.error('🔒 解密消息失败:', error)
              data = rawData // 解密失败时使用原始数据
            }
          } else {
            data = rawData
          }
          
          this.callback(data)
        } catch (error) {
          console.error('🌐 WebSocket 消息处理错误:', error)
        }
      }
      
      // 监听socket错误信息
      this.ws.onerror = (e) => {
        clearTimeout(connectionTimeout) // 清除连接超时定时器
        console.error('🌐 WebSocket 错误:', e)
      }
      
      // 监听socket关闭
      this.ws.onclose = (e) => {
        clearTimeout(connectionTimeout) // 清除连接超时定时器
        console.log('🌐 WebSocket 关闭:', e)
        this.onClose(e)
      }
    } catch (error) {
      clearTimeout(connectionTimeout) // 清除连接超时定时器
      console.error('🌐 WebSocket 连接创建失败:', error)
      this.onClose({ code: 1006, reason: "连接创建失败" })
    }
  }

  /**
   * @description: 初始化加密
   * @param {*}
   * @return {*}
   */
  initEncryption() {
    if (!this.enableEncryption || !this.crypto) {
      return
    }
    
    try {
      // 检查WebSocket连接状态
      if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
        console.error('🔒 初始化加密失败: WebSocket未连接或未就绪')
        
        // 如果WebSocket未就绪，稍后重试
        setTimeout(() => {
          console.log('🔒 重试初始化加密...')
          this.initEncryption()
        }, 1000)
        return
      }
      
      // 生成SM2密钥对并发送公钥
      const publicKey = this.crypto.initKeyPair()
      this.send({
        type: WEBSOCKET_TYPE.KEY_EXCHANGE_INIT,
        publicKey: publicKey
      })
      console.log('🔒 已发送密钥交换初始化请求')
    } catch (error) {
      console.error('🔒 初始化加密失败:', error)
    }
  }
  
  /**
   * @description: 处理密钥交换
   * @param {*} data
   * @return {*}
   */
  handleKeyExchange(data) {
    if (!this.enableEncryption || !this.crypto) {
      return
    }
    
    try {
      console.log('🔒 处理密钥交换消息:', {
        type: data.type,
        hasServerPublicKey: !!data.serverPublicKey,
        hasSuccess: !!data.success
      })
      
      // 处理初始化响应（服务器发送公钥）
      if (data.type === WEBSOCKET_TYPE.KEY_EXCHANGE_INIT && data.serverPublicKey) {
        // 设置服务器公钥
        console.log('🔒 收到服务器公钥:', data.serverPublicKey.substring(0, 20) + '...')
        this.crypto.setServerPublicKey(data.serverPublicKey)
        
        // 生成SM4密钥并加密发送
        try {
          const encryptedKey = this.crypto.generateAndEncryptSM4Key()
          console.log('🔒 生成的加密密钥:', encryptedKey.substring(0, 20) + '...')
          
          const message = {
            type: WEBSOCKET_TYPE.KEY_EXCHANGE_COMPLETE,
            encryptedKey: encryptedKey
          }
          console.log('KEY_EXCHANGE_COMPLETE消息', message)
          
          
          const result = this.send(numericMessage)
          console.log('🔒 密钥交换完成消息发送结果:', result)
        } catch (error) {
          console.error('🔒 生成或发送SM4密钥失败:', error)
        }
      }
      
      // 处理交换成功响应
      if (data.type === WEBSOCKET_TYPE.KEY_EXCHANGE_SUCCESS && data.success) {
        console.log('🔒 加密通道建立成功!')
        this.isEncrypted = true
      }
      
      // 兼容旧版本服务器的响应格式
      if (data.type === 'KEY_EXCHANGE') {
        if (data.serverPublicKey) {
          // 设置服务器公钥
          this.crypto.setServerPublicKey(data.serverPublicKey)
          
          // 生成SM4密钥并加密发送
          const encryptedKey = this.crypto.generateAndEncryptSM4Key()
          this.send({
            type: WEBSOCKET_TYPE.KEY_EXCHANGE_COMPLETE,
            encryptedKey: encryptedKey
          })
          console.log('发KEY_EXCHANGE_COMPLETE类型的消息')
        }
        
        if (data.success) {
          console.log('🔒 加密通道建立成功! (兼容模式)')
          this.isEncrypted = true
        }
      }
    } catch (error) {
      console.error('🔒 处理密钥交换失败:', error)
    }
  }

  /**
   * @description: 发送消息
   * @param {*} data
   * @return {*}
   * @author: gumingchen
   */
  send(data) {
    if (this.mockMode) {
      console.log('Mock WebSocket:', data)
      return
    }
    
    // 检查WebSocket连接状态
    if (!this.ws) {
      console.error('🌐 WebSocket 发送失败: 连接对象不存在')
      return false
    }
    
    console.log('🌐 WebSocket 当前状态:', {
      readyState: this.ws.readyState,
      status: this.status,
      readyStateText: ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'][this.ws.readyState] || '未知'
    })
    
    if (this.ws.readyState !== WebSocket.OPEN) {
      console.error('🌐 WebSocket 发送失败: 连接未建立或未就绪', {
        readyState: this.ws.readyState,
        readyStateText: ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'][this.ws.readyState] || '未知',
        type: data.type ? (WEBSOCKET_TYPE[data.type] || data.type) : '未知类型'
      })
      return false
    }
    
    // 加密消息
    let sendData
    if (this.enableEncryption && this.isEncrypted && 
        data.type !== WEBSOCKET_TYPE.KEY_EXCHANGE_INIT && 
        data.type !== WEBSOCKET_TYPE.KEY_EXCHANGE_COMPLETE) {
      try {
        const encrypted = this.crypto.encryptMessage(data)
        sendData = {
          encrypted: true,
          payload: encrypted
        }
        console.log('🔒 消息已加密',encrypted)
      } catch (error) {
        console.error('🔒 加密消息失败:', error)
        sendData = data // 加密失败时使用原始数据
      }
    } else {
      sendData = data
    }
    
    console.log('🌐 WebSocket 发送消息:', {
      type: data.type ? (WEBSOCKET_TYPE[data.type] || data.type) : '加密消息',
      data: this.enableEncryption && this.isEncrypted ? '内容已加密' : data
    })
    
    try {
      // 转换为JSON字符串
      const jsonStr = JSON.stringify(sendData)
      console.log('🌐 WebSocket 发送的JSON字符串:', jsonStr.substring(0, 100) + (jsonStr.length > 100 ? '...' : ''))
      
      this.ws.send(jsonStr)
      console.log('🌐 WebSocket 消息发送成功')
      return true
    } catch (error) {
      console.error('🌐 WebSocket 发送消息失败:', error)
      return false
    }
  }

  /**
   * @description: 关闭weibsocket 主动关闭不会触发重连
   * @param {*}
   * @return {*}
   * @author: gumingchen
   */
  close() {
    console.log('🌐 WebSocket 主动关闭连接')
    this.status = 2
    this.ws.close()
  }

  /**
   * @description: socket关闭事件
   * @param {*}
   * @return {*}
   * @author: gumingchen
   */
  onClose(e) {
    console.error('🌐 WebSocket 连接关闭:', e)
    
    // 清除心跳定时器
    if (this.pingInterval) {
      clearInterval(this.pingInterval)
      this.pingInterval = null
    }
    
    // 清除稳定连接计时器
    if (this.stableTimeout) {
      clearTimeout(this.stableTimeout)
      this.stableTimeout = null
    }
    
    // 重置连接稳定状态
    this.connectionStable = false
    
    // 如果是主动关闭，不重连
    this.status = this.status === 2 ? this.status : 0
    this.isEncrypted = false // 重置加密状态
    console.log('🔒 WebSocket关闭，加密状态已重置')
    
    // 非主动关闭时尝试重连
    if (this.status === 0) {
      // 限制最大重连次数
      if (this.reconnectAttempts >= this.maxReconnectAttempts) {
        console.error(`🌐 WebSocket 已达到最大重连次数 ${this.maxReconnectAttempts}，停止重连`)
        return
      }
      
      // 计算重连延迟时间（指数退避算法）
      let delay = this.reconnect
      if (this.reconnectBackoff) {
        // 使用指数退避算法：基础时间 * (1.3^尝试次数)，但不超过60秒
        delay = Math.min(this.reconnect * Math.pow(1.3, this.reconnectAttempts), 60000)
      }
      
      this.reconnectAttempts++
      console.log(`🌐 WebSocket 将在 ${delay}ms 后进行第 ${this.reconnectAttempts} 次重连尝试...`)
      
      setTimeout(() => {
        if (this.status === 0) {
          console.log(`🌐 WebSocket 正在进行第 ${this.reconnectAttempts} 次重连...`)
          this.connect()
        }
      }, delay)
    } else {
      // 如果是主动关闭，重置重连计数
      this.reconnectAttempts = 0
    }
  }

  /**
   * @description: 心跳机制
   * @param {*}
   * @return {*}
   * @author: gumingchen
   */
  heartHandler() {
    // 清除可能存在的旧心跳
    if (this.pingInterval) {
      clearInterval(this.pingInterval)
    }
    
    const data = {
      type: WEBSOCKET_TYPE.HEARTBEAT
    }
    
    // 上次心跳响应时间
    let lastPongTime = Date.now()
    
    // 心跳超时检测时间增加
    const heartbeatTimeout = 45000 // 从30秒增加到45秒，与后端保持一致
    
    this.pingInterval = setInterval(() => {
      if (this.status === 1) {
        // 检查上次心跳响应是否超时
        const now = Date.now()
        if (now - lastPongTime > heartbeatTimeout) {
          console.error('🌐 WebSocket 心跳响应超时，关闭连接')
          // 清除心跳定时器
          clearInterval(this.pingInterval)
          this.pingInterval = null
          
          // 关闭连接，触发重连
          if (this.ws) {
            this.ws.close()
          }
          return
        }
        
        console.log('🌐 WebSocket 发送心跳')
        try {
          this.ws.send(JSON.stringify(data))
          
          // 设置心跳响应处理函数（如果尚未设置）
          if (!this._heartbeatHandler) {
            this._heartbeatHandler = true
            
            // 覆盖原始消息处理函数，添加心跳响应处理
            const originalOnMessage = this.ws.onmessage
            this.ws.onmessage = (e) => {
              // 更新心跳响应时间
              try {
                const data = JSON.parse(e.data)
                if (data && data.type === WEBSOCKET_TYPE.HEARTBEAT) {
                  lastPongTime = Date.now()
                  console.log('🌐 WebSocket 收到心跳响应')
                }
              } catch (err) {
                // 忽略解析错误
              }
              
              // 调用原始消息处理函数
              if (originalOnMessage) {
                originalOnMessage(e)
              }
            }
          }
        } catch (error) {
          console.error('🌐 WebSocket 发送心跳失败:', error)
          // 发送失败时关闭连接
          clearInterval(this.pingInterval)
          this.pingInterval = null
          if (this.ws) {
            this.ws.close()
          }
        }
      } else {
        console.log('🌐 WebSocket 心跳停止')
        clearInterval(this.pingInterval)
        this.pingInterval = null
      }
    }, this.ping)
  }
}
